using System;

using AGG.UI;
using AGG.Image;
using AGG.VertexSource;
using AGG.RasterizerScanline;

namespace AGG
{
    public class rounded_rect_application : MatchParentBoundsWidget
    {
        double[] m_x = new double[2];
        double[] m_y = new double[2];
        double m_dx;
        double m_dy;
        int m_idx;
        AGG.UI.SliderWidget m_radius;
        AGG.UI.SliderWidget m_gamma;
        AGG.UI.SliderWidget m_offset;
        AGG.UI.CheckBoxWidget m_white_on_black;
        AGG.UI.CheckBoxWidget m_DrawAsOutlineCheckBox;


        public rounded_rect_application()
        {
            m_idx = (-1);
            m_radius = new AGG.UI.SliderWidget(10, 10, 600-10,   19);
            m_gamma = new AGG.UI.SliderWidget(10, 10+20, 600-10, 19+20);
            m_offset = new AGG.UI.SliderWidget(10, 10+40, 600-10, 19+40);
            m_white_on_black = new CheckBoxWidget(10, 10+60, "White on black");
            m_DrawAsOutlineCheckBox = new CheckBoxWidget(10 + 180, 10 + 60, "Fill Rounded Rect");

            m_radius.ValueChanged += new SliderWidget.ValueChangedEventHandler(NeedsRedraw);
            m_gamma.ValueChanged += new SliderWidget.ValueChangedEventHandler(NeedsRedraw);
            m_offset.ValueChanged += new SliderWidget.ValueChangedEventHandler(NeedsRedraw);
            m_white_on_black.CheckedStateChanged += new CheckBoxWidget.CheckedStateChangedEventHandler(NeedsRedraw);
            m_DrawAsOutlineCheckBox.CheckedStateChanged += new CheckBoxWidget.CheckedStateChangedEventHandler(NeedsRedraw);

            m_x[0] = 100;   m_y[0] = 100;
            m_x[1] = 500;   m_y[1] = 350;
            AddChild(m_radius);
            AddChild(m_gamma);
            AddChild(m_offset);
            AddChild(m_white_on_black);
            AddChild(m_DrawAsOutlineCheckBox);
            m_gamma.label("gamma={0:F3}");
            m_gamma.range(0.0, 3.0);
            m_gamma.value(1.8);

            m_radius.label("radius={0:F3}");
            m_radius.range(0.0, 50.0);
            m_radius.value(25.0);

            m_offset.label("subpixel offset={0:F3}");
            m_offset.range(-2.0, 3.0);

            m_white_on_black.TextColor = new RGBA_Bytes(127, 127, 127);
            m_white_on_black.inactive_color(new RGBA_Bytes(127, 127, 127));

            m_DrawAsOutlineCheckBox.TextColor = new RGBA_Doubles(.5, .5, .5).GetAsRGBA_Bytes();
            m_DrawAsOutlineCheckBox.inactive_color(new RGBA_Bytes(127, 127, 127));
        }

        void NeedsRedraw(object sender, EventArgs e)
        {
            Invalidate();
        }


        public override void OnDraw(Graphics2D graphics2D)
        {
            GammaLookUpTable gamma = new GammaLookUpTable(m_gamma.value());
            IBlenderByte NormalBlender = new BlenderBGRA();
            IBlenderByte GammaBlender = new BlenderGammaBGRA(gamma);
            ImageBuffer rasterNormal = new ImageBuffer();
            rasterNormal.Attach(graphics2D.DestImage, NormalBlender);
            ImageBuffer rasterGamma = new ImageBuffer();
            rasterGamma.Attach(graphics2D.DestImage, GammaBlender);
            ImageClippingProxy clippingProxyNormal = new ImageClippingProxy(rasterNormal);
            ImageClippingProxy clippingProxyGamma = new ImageClippingProxy(rasterGamma);

            clippingProxyNormal.clear(m_white_on_black.Checked ? new RGBA_Doubles(0, 0, 0) : new RGBA_Doubles(1, 1, 1));

            ScanlineRasterizer ras = new ScanlineRasterizer();
            ScanlineCachePacked8 sl = new ScanlineCachePacked8();

            VertexSource.Ellipse e = new VertexSource.Ellipse();

            // TODO: If you drag the control circles below the bottom of the window we get an exception.  This does not happen in AGG.
            // It needs to be debugged.  Turning on clipping fixes it.  But standard agg works without clipping.  Could be a bigger problem than this.
            //ras.clip_box(0, 0, width(), height());

            // Render two "control" circles
            e.init(m_x[0], m_y[0], 3, 3, 16);
            ras.add_path(e);
            agg_renderer_scanline.Default.render_scanlines_aa_solid(clippingProxyNormal, ras, sl, new RGBA_Bytes(127, 127, 127));
            e.init(m_x[1], m_y[1], 3, 3, 16);
            ras.add_path(e);
            agg_renderer_scanline.Default.render_scanlines_aa_solid(clippingProxyNormal, ras, sl, new RGBA_Bytes(127, 127, 127));

            double d = m_offset.value();

            // Creating a rounded rectangle
            VertexSource.RoundedRect r = new VertexSource.RoundedRect(m_x[0] + d, m_y[0] + d, m_x[1] + d, m_y[1] + d, m_radius.value());
            r.normalize_radius();

            // Drawing as an outline
            if (!m_DrawAsOutlineCheckBox.Checked)
            {
                conv_stroke p = new conv_stroke(r);
                p.width(1.0);
                ras.add_path(p);
            }
            else
            {
                ras.add_path(r);
            }

            agg_renderer_scanline.Default.render_scanlines_aa_solid(clippingProxyGamma, ras, sl, m_white_on_black.Checked ? new RGBA_Bytes(255, 255, 255) : new RGBA_Bytes(0, 0, 0));

            base.OnDraw(graphics2D);
        }


        public override void OnMouseDown(MouseEventArgs mouseEvent)
        {
            if(mouseEvent.Button == MouseButtons.Left)
            {
                for (int i = 0; i < 2; i++)
                {
                    double x = mouseEvent.X;
                    double y = mouseEvent.Y;
                    if(Math.Sqrt( (x-m_x[i]) * (x-m_x[i]) + (y-m_y[i]) * (y-m_y[i]) ) < 5.0)
                    {
                        m_dx = x - m_x[i];
                        m_dy = y - m_y[i];
                        m_idx = i;
                        break;
                    }
                }
            }

            base.OnMouseDown(mouseEvent);
        }


        public override void OnMouseMove(MouseEventArgs mouseEvent)
        {
            if (mouseEvent.Button == MouseButtons.Left)
            {
                if(m_idx >= 0)
                {
                    m_x[m_idx] = mouseEvent.X - m_dx;
                    m_y[m_idx] = mouseEvent.Y - m_dy;
                    Invalidate();
                }
            }

            base.OnMouseMove(mouseEvent);
        }

        override public void OnMouseUp(MouseEventArgs mouseEvent)
        {
            m_idx = -1;
            base.OnMouseUp(mouseEvent);
        }
        
        public static void StartDemo()
        {
            GuiHalFactory.SetGuiBackend(GuiHalFactory.KnownGuiFactoriesIndexes.WindowsFormsBitmap);
            GuiHalSurface primaryWindow = GuiHalFactory.CreatePrimarySurface(600, 400, GuiHalSurface.CreateFlags.Resizable, GuiHalSurface.PixelFormat.PixelFormatBgra32);

            primaryWindow.Caption = "AGG Example. Rounded rectangle with gamma-correction & stuff";

            primaryWindow.AddChild(new rounded_rect_application());
            primaryWindow.Run();
        }

        [STAThread]
        public static void Main(string[] args)
        {
        	StartDemo();
        }
    };
}
